package com.xishu.service.print;

import cn.hutool.core.convert.Convert;
import com.xishu.bo.DetailReport;
import com.xishu.bo.printer.PrinterItem;
import com.xishu.bo.printer.PrinterLine;
import com.xishu.bo.response.Report;
import com.xishu.client.PrinterClient;
import com.xishu.config.Config;
import com.xishu.config.Constant;
import com.xishu.entity.Company;
import com.xishu.entity.User;
import com.xishu.entity.hardware.Printer;
import com.xishu.entity.hardware.PrinterFailedResult;
import com.xishu.entity.order.CalTips;
import com.xishu.entity.order.CashPay;
import com.xishu.entity.order.Order;
import com.xishu.entity.order.OrderItem;
import com.xishu.entity.shop.*;
import com.xishu.exception.ResponseStatusException;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.*;
import com.xishu.service.order.base.OrderService;
import com.xishu.service.print.kitchen.KitchenService;
import com.xishu.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.*;

/**
 * 各种打印场景
 */
public class PrinterService implements Tools {
    private static Logger logger = LoggerFactory.getLogger(PrinterService.class);
    private static PrinterService instance = new PrinterService();
    private KitchenService kitchenService = KitchenService.getInstance();
    private CommonService commonService = CommonService.getInstance();
    private PrinterClient printerClient = PrinterClient.getInstance();
    private OrderService orderService = OrderService.getInstance();
    private CompanyService companyService = CompanyService.getInstance();
    private LangService langService = LangService.getInstance();
    private PayTypeService payTypeService = PayTypeService.getInstance();
    private StringService stringService = StringService.getInstance();

    public static final int LINE_LENGTH = 48;
    public static final int ONE_ITEM_LENGTH = LINE_LENGTH / 3;
    private Config config = Config.getInstance();

    private PrinterService() {
    }

    public static PrinterService getInstance() {
        return instance;
    }

    public void printerOrderItemList(Order orderInDb, List<Long> orderItemIdList) throws Exception {
        KitchenService.getInstance().printerOrderItemList(orderInDb, orderItemIdList);

        //如果是 外卖，快餐模式下的堂食，以及总二维码点餐（无论是堂食还是外卖）下才会出打包单，也就是说这个订单没有餐桌号
        if (!orderService.isFoodTableOrder(orderInDb)) {
            Order cloneOrder = (Order) ClassUtil.clone(orderInDb);
            List<OrderItem> orderItemDetailList = cloneOrder.getOrderItemDetailList();
            List<OrderItem> filterOrderItem = orderItemDetailList.stream().filter(s -> {
                return s.getCheckout() && s.getConfirmItem();
            }).collect(Collectors.toList());
            cloneOrder.setOrderItemDetailList(filterOrderItem);
            Printer reqPrinter = new Printer();
            reqPrinter.setShopId(orderInDb.getShopId());
            reqPrinter.setEntity(true);
            reqPrinter.setPacking(true);
            Optional<Printer> printerOptional = commonService.searchOneOptional(reqPrinter);
            if (printerOptional.isPresent()) {
                printOrder(cloneOrder, printerOptional.get().getId(), true, false);
            }
        }
    }

    public boolean sendOrderToKitchen(Order orderInDb, Long printerId) throws Exception {
        return KitchenService.getInstance().sendOrderToKitchen(orderInDb, printerId);
    }

    /**
     * 查询打印机
     *
     * @param printerId
     * @return
     * @throws Exception
     */
    public Optional<Printer> findPrinter(Long printerId) throws Exception {
        Printer printer = commonService.findEntity(printerId, Printer.class);

        if (printer == null) {
            return Optional.empty();
        }

        if (getBoolean(printer.getFlagDelete())) {
            return Optional.empty();
        }

        return Optional.of(printer);
    }

    /**
     * 查询吧台的打印机
     *
     * @param shopId
     * @return
     */
    private Printer findBarCounterPrinter(Long shopId) {
        Printer printer = new Printer();
        printer.setShopId(shopId);
        printer.setLocation(Constant.PRINTER_LOCATION_BAR_COUNTER);
        return commonService.searchOne(printer);
    }

    /**
     * 查询厨房打印机
     *
     * @param shopId
     * @return
     */
    private Printer findKitchenPrinter(Long shopId) {
        Printer printer = new Printer();
        printer.setShopId(shopId);
        printer.setLocation(Constant.PRINTER_LOCATION_KITCHEN);
        return commonService.searchOne(printer);
    }


    /**
     * 打印新的订单
     *
     * @param reqFoodTable
     * @throws Exception
     */
    public void printerAddNewOrder(FoodTable reqFoodTable, Long printerId) throws Exception {
        Long foodTableId = reqFoodTable.getId();

        FoodTable foodTable = FoodTableService.getInstance().findTableById(foodTableId);
        VerifyUtil.verify(() -> foodTable != null, ResponseStatus.ORDER_DELETED);
        Long shopId = foodTable.getShopId();
        Shop shop = ShopService.getInstance().findShopById(shopId);
        Company company = commonService.findEntity(shop.getCompanyId(), Company.class);
        Printer barCounterPrinter = commonService.findEntity(printerId, Printer.class);
        Boolean zh = commonService.isZh(barCounterPrinter.getLang());

        VerifyUtil.verify(() -> barCounterPrinter != null, ResponseStatus.BAR_COUNTER_PRINTER_NOT_CONFIG);
        VerifyUtil.verify(() -> !getBoolean(barCounterPrinter.flagDelete), ResponseStatus.BAR_COUNTER_PRINTER_NOT_CONFIG);
        String printerSn = AES.decrypt(barCounterPrinter.getPrinterSn());

        //生成打印字符串
        ArrayList<PrinterLine> printerLines = new ArrayList<>();

        //打印机的LOGO
        printerLines.add(printerClient.newLogo());

        if (isNotEmpty(company.getPrintCompanyName())) {
            //公司名称
            printerLines.add(printerClient.newLine(company.getPrintCompanyName(), true, true));
        } else {
            printerLines.add(printerClient.newLine(companyService.getCompanyName(company, zh), true, true));
        }
        //餐厅名称
        printerLines.add(printerClient.newLine("(" + langService.getShopName(shop, zh) + ")", true, null));

        //餐厅地址
        printerLines.addAll(CommonPrintService.getInstance().getShopAddressLine(shop, zh));

        //餐厅电话
        if (isNotEmpty(shop.getPhone())) {
            printerLines.add(printerClient.newLine(config.label_phone(zh) + getString(shop.getPhone()), null, null));
        }

        //分隔符
        printerLines.add(printerClient.printSeparator());

        //每日订单
        PrinterLine orderNoLine = new PrinterLine();
        PrinterItem orderNoLabelItem = new PrinterItem();
        String perDayOrder = config.label_per_day_order(zh) + "：";

        if (!getBoolean(zh)) {
            perDayOrder = config.label_per_day_order(zh) + ":";
        }

        orderNoLabelItem.setContent(perDayOrder);
        orderNoLabelItem.setBold(true);
        orderNoLabelItem.setDoubleShow(true);
        orderNoLine.add(orderNoLabelItem);

        //用unicode去查询订单
        PrinterItem orderNoItem = new PrinterItem();
        Order order = orderService.findOrder(foodTable);
        VerifyUtil.verify(() -> !getBoolean(order.getFlagDelete()), ResponseStatus.ORDER_DELETED);

        String orderNoStr = getOrderNoStr(order);
        orderNoItem.setContent(orderNoStr);
        orderNoItem.setBold(true);
        orderNoItem.setDoubleShow(true);
        orderNoLine.add(orderNoItem);
        printerLines.add(orderNoLine);

        //桌号
        PrinterLine foodTableLine = new PrinterLine();
        PrinterItem foodTableLabelItem = new PrinterItem();
        foodTableLabelItem.setContent(config.label_food_table_no(zh));
        foodTableLabelItem.setBold(true);
        foodTableLabelItem.setDoubleShow(true);
        foodTableLine.add(foodTableLabelItem);

        PrinterItem foodTableItem = new PrinterItem();
        if (order.getShowNo() != null) {
            foodTableItem.setContent(order.getCode() + "-" + order.getShowNo());
        } else {
            foodTableItem.setContent(foodTable.getCode());
        }

        foodTableItem.setBold(true);
        foodTableItem.setDoubleShow(true);
        foodTableLine.add(foodTableItem);

        printerLines.add(foodTableLine);

        //负责员工
        if (isNotEmpty(foodTable.getWaiterName())) {

            PrinterLine waiterLine = new PrinterLine();
            PrinterItem waiterLableItem = new PrinterItem();
            waiterLableItem.setContent(config.label_waiter(zh));
            waiterLine.add(waiterLableItem);

            PrinterItem waiterItem = new PrinterItem();
            waiterItem.setContent(foodTable.getWaiterName());
            waiterLine.add(waiterItem);

            printerLines.add(waiterLine);
        }

        //开台时间
        PrinterLine openTimeLine = new PrinterLine();
        PrinterItem openTimeLabelItem = new PrinterItem();
        openTimeLabelItem.setContent(config.label_open_time(zh));
        openTimeLine.add(openTimeLabelItem);

        PrinterItem openTimeItem = new PrinterItem();

        if (order != null) {
            openTimeItem.setContent(order.getCreateDate());
        }

        openTimeLine.add(openTimeItem);

        printerLines.add(openTimeLine);

        //就餐人数
        if (getInt(foodTable.getDiners()) > 0) {
            PrinterLine personLine = new PrinterLine();
            PrinterItem personLabelItem = new PrinterItem();
            personLabelItem.setContent(config.label_dinner_number(zh));
            personLine.add(personLabelItem);

            PrinterItem personItem = new PrinterItem();
            personItem.setContent(foodTable.getDiners() + config.label_person(zh));
            personLine.add(personItem);

            printerLines.add(personLine);
        }

        //如果有服务员，添加显示服务员
        if (isNotEmpty(foodTable.getWaiterId())) {
            Long waiterId = foodTable.getWaiterId();
            Optional<User> userOptional = commonService.searchOneOptional(waiterId, User.class);
            if (userOptional.isPresent()) {
                User waiter = userOptional.get();

                PrinterLine waiterLine = new PrinterLine();
                PrinterItem waiterLabelItem = new PrinterItem();
                waiterLabelItem.setContent(config.label_waiter_name(zh));
                waiterLine.add(waiterLabelItem);

                PrinterItem personItem = new PrinterItem();
                personItem.setContent(waiter.getNickName());
                waiterLine.add(personItem);

                printerLines.add(waiterLine);
            } else {
                logger.info("can not find the waiter {}", waiterId);
            }
        }

        //分隔符
        printerLines.add(printerClient.printTwoLineSeparator());

        //扫描参数二维码
        String endPoint = config.getEndPoint();
        String qrCode = String.format(endPoint + "/customer/index.html/#/pages/menu?sid=%s&r=%s&c=%s&uid=%s&type=normal", shopId, foodTable.getRow(), foodTable.getColumn(), getInt(foodTable.getUniqueCode()));
        printerLines.add(printerClient.newQrCode(qrCode));

        if (getBoolean(shop.getShopConfig().getOpenOrderQRContent())) {
            //及时（点餐）二维码提示(用户自己设置的)中文
            if (zh && isNotEmpty(shop.getShopConfig().getOrderQRContent_zh())) {
                PrinterLine printerLine = printerClient.newLine(shop.getShopConfig().getOrderQRContent_zh(), true, null);
                printerLine.getPrinterItem().setDoubleShow(true);
                printerLines.add(printerLine);
            }
            //及时（点餐）二维码提示(用户自己设置的)英文
            if (!zh && isNotEmpty(shop.getShopConfig().getOrderQRContent_en())) {

                PrinterLine printerLine = printerClient.newLine(shop.getShopConfig().getOrderQRContent_en(), true, null);
                printerLine.getPrinterItem().setDoubleShow(true);
                printerLines.add(printerLine);
            }
        }


        Long sceneId = foodTable.getSceneId();
        //只有先付款，才打印麻烦下单后先付款
        if (sceneId != null) {
            Optional<Scene> sceneOptional = commonService.searchOneOptional(sceneId, Scene.class);
            if (sceneOptional.isPresent()) {
                Scene scene = sceneOptional.get();
                Optional<RunModuleScene> runModuleSceneOptional = scene.getRunModuleSceneList().stream().filter(p -> {
                    return getInt(p.getType()) == RUN_MODEL_TYPE_FOOD_TABLE_WAITER_QR;
                }).findFirst();

                if (runModuleSceneOptional.isPresent() && getBoolean(runModuleSceneOptional.get().getPayFirst())) {
                    printerLines.add(printerClient.newLine(config.label_pay_first(zh), true, null));
                } else {
                    logger.info("its not the pay first scene");
                }
            } else {
                logger.info("can not find the scene {}", sceneId);
            }
        } else {
            logger.info("can not find the scene id  for food table {}", foodTable.getId());
        }

        printerClient.printList(printerLines, printerSn, printerId);
    }


    /**
     * 打印整个订单
     *
     * @param order
     * @param zh
     * @return
     */
    private ArrayList<PrinterLine> printSmallTicketOrderItem(Order order, boolean zh, boolean packingOrder) throws Exception {
        logger.info("print order item detail in small ticket {}", order.getId());

        final int NUMBER_SIZE = 6;
        final int PRICE_SIZE = 10;

        //其它模式
        ArrayList<PrinterLine> printerLineList = new ArrayList<>();

        for (OrderItem orderItem : getList(order.getOrderItemDetailList())) {
            PrinterLine orderItemLine = new PrinterLine();
            printerLineList.add(orderItemLine);
            orderItemLine.setDirect(true);
            orderItemLine.setNewLine(false);

            //数量
            PrinterItem countItem = new PrinterItem();
            String countString = null;

            if (orderItem.getCount() < 10) {
                countString = "   " + orderItem.getCount();
            } else {
                countString = "  " + orderItem.getCount();
            }

            int nameAfterSpaceSize = NUMBER_SIZE - printerClient.getGbkLength(countString);

            //中文往后添加1个汉字距离，也就是2个空格
            if (zh) {
                nameAfterSpaceSize = nameAfterSpaceSize + 2;
            }

            logger.info("nameAfterSpaceSize is {}", nameAfterSpaceSize);
            String spaceString = printerClient.generateSpace(nameAfterSpaceSize);
            countString = countString + spaceString;
            logger.info("space string is{}end", countString);

            //名称
            PrinterItem itemNameItem = new PrinterItem();
            StringBuilder itemNameBuilder = new StringBuilder();

            String printItemName = langService.getOrderItemName(orderItem, zh);

            itemNameBuilder.append(printItemName);

            String itemName = null;
            //加了外卖标记，标粗
            if (getBoolean(orderItem.getTakeout()) && !orderService.isTakeoutOrder(order)) {
                //计算长度
                itemNameBuilder.append(String.format("(%s)", config.label_take_out(zh)));
                itemName = itemNameBuilder.toString();
            } else {
                itemName = itemNameBuilder.toString();
            }

            int itemNameLength = printerClient.getGbkLength(itemName);
            //计算长度，如果超长了，需要另起一行
            //数字默认占10个长度
            //金额默认占6个长度
            //小于，说明只有一行 乘以2是因为字体变大了
            if (itemNameLength <= LINE_LENGTH - NUMBER_SIZE - PRICE_SIZE) {
                countItem.setContent(getPrintContent(countString, packingOrder));

                orderItemLine.add(countItem);

                //前面固定位置
                String content = null;
                content = itemName;

                logger.debug("content is{} end", content);

                //打包单，需要把显示拉高
                itemNameItem.setContent(getPrintContent(content, packingOrder));

                orderItemLine.add(itemNameItem);

                //服务员打印整个订单的时候，需要有价格
                //如果是发送到厨房的打印单，不需要有价格
                //添加价格,并添加千位分隔符
                PrinterItem priceItem = new PrinterItem();
                String price = BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(orderItem.getItemPrice() * orderItem.getCount())));
                //补空格
                int addSpaceSize = LINE_LENGTH - printerClient.getGbkLength(countString) - printerClient.getGbkLength(content) - printerClient.getGbkLength("$" + price);
                logger.debug("addSpaceSize size {}", addSpaceSize);
                String priceContent = printerClient.generateSpace(addSpaceSize) + "$" + price;
                priceItem.setContent(priceContent);
                orderItemLine.add(priceItem);

                logger.debug("will add order detail");
            } else {
                countItem.setContent(getPrintContent(countString, packingOrder));
                orderItemLine.add(countItem);

                //分行两行
                //先添加第一行
                List<String> contentList = printerClient.getStringList(itemName, LINE_LENGTH - NUMBER_SIZE - PRICE_SIZE, zh);
                String firstItemContent = contentList.get(0);

                itemNameItem.setContent(getPrintContent(firstItemContent, packingOrder));

                orderItemLine.add(itemNameItem);

                //服务员打印整个订单的时候，需要有价格
                //如果是发送到厨房的打印单，不需要有价格
                //添加价格,并添加千位分隔符
                PrinterItem priceItem = new PrinterItem();
                String price = BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(orderItem.getItemPrice() * orderItem.getCount())));
                //补空格
                int addSpaceSize = LINE_LENGTH - printerClient.getGbkLength(countString) - printerClient.getGbkLength(firstItemContent) - printerClient.getGbkLength("$" + price);
                logger.info("addSpaceSize size {}", addSpaceSize);
                String priceContent = printerClient.generateSpace(addSpaceSize) + "$" + price;
                priceItem.setContent(priceContent);
                orderItemLine.add(priceItem);

                logger.info("will add order detail");

                //添加剩下的所有行
                List<String> leftContentList = contentList.subList(1, contentList.size());

                for (String secondContent : leftContentList) {
                    PrinterLine printerSecondLine = new PrinterLine();
                    PrinterItem printerItem = new PrinterItem();
                    //这里只能加一半的空格，因为大小会翻倍
                    printerItem.setContent(getPrintContent(printerClient.generateSpace(NUMBER_SIZE) + secondContent, packingOrder));
                    printerSecondLine.add(printerItem);
                    printerLineList.add(printerSecondLine);
                }
            }

            //如果还有规格项，再依次添加规格项
            if (isNotEmpty(orderItem.getItemDetailList())) {
                List<PrinterLine> printerLines = printSmallTicketOrderItemDetail(orderItem.getItemDetailList(), zh);
                printerLineList.addAll(printerLines);
            } else if (getBoolean(orderItem.getSetMenu())) {
                List<PrinterLine> printerLines = printSmallTicketOrderItemDetail_SetMenu(orderItem, zh);
                printerLineList.addAll(printerLines);
            }
            if (isNotEmpty(orderItem.getRemarks())) {
                String space = printerClient.generateSpace(10);
                if (getBoolean(orderItem.getSetMenu())) {
                    space = printerClient.generateSpace(12);
                }
                PrinterLine printerLine = new PrinterLine();
                printerLine.setDirect(true);
                PrinterItem printerItem = new PrinterItem();
                printerItem.setContent(space + config.label_remark_print(zh) + orderItem.getRemarks());
                printerLine.add(printerItem);
                printerLineList.add(printerLine);

            }

        }
        return printerLineList;
    }

    /**
     * 获取菜品的名称
     *
     * @param item
     * @param zh
     * @return
     */
    private String getItemName(Item item, boolean zh) {
        if (zh) {
            return StringUtils.stripEnd(item.getName_zh(), null);
        } else {
            return StringUtils.stripEnd(item.getName_en(), null);
        }
    }


    /**
     * 打印小票的时候，打印套餐
     *
     * @param orderItem
     * @param zh
     * @return
     */
    public List<PrinterLine> printSmallTicketOrderItemDetail_SetMenu(OrderItem orderItem, boolean zh) throws Exception {
        logger.info("print order item set menu {}", orderItem.getId());
        List<PrinterLine> printerLineList = new ArrayList<>();

        for (SetMenuOneItem setMenuOneItem : getList(orderItem.getSetMenuOneItemList())) {
            //过滤掉不加配的菜品
            for (Item item : getList(setMenuOneItem.getItemList())) {
                if (getLong(item.getId()) == 0) {
                    continue;
                }

                //如果配置了不打印名称，则不打印，只在小票里面不打印
                if (!getBoolean(setMenuOneItem.getNotPrintItemName())) {
                    String itemName = getItemName(ItemService.getInstance().findItem(item.getId()), zh);
                    itemName = CommonPrintService.getInstance().getItemNameWithCount(itemName, item);

                    //英文单词要少7个空格
                    List<String> itemNameList = printerClient.getStringList(itemName, zh ? LINE_LENGTH - 18 : LINE_LENGTH - 18, zh);

                    for (String name : itemNameList) {
                        //添加名称,单独一行
                        PrinterLine detailNameLine = new PrinterLine();
                        detailNameLine.setDirect(true);

                        //英文单词要少7个空格
                        String nameContent = printerClient.generateSpace(zh ? 12 : 12) + name;
                        PrinterItem detailNamePrinterItem = new PrinterItem();
                        detailNamePrinterItem.setContent(nameContent);
                        detailNameLine.add(detailNamePrinterItem);
                        printerLineList.add(detailNameLine);
                    }
                }

                //添加规格,添加一个判断，熊猫单不一定有细节
                if (item.getItemDetailList() != null) {
                    printerLineList.addAll(printSmallTicketOrderItemDetail_SetMenu(item.getItemDetailList(), zh));
                }


            }
        }

        return printerLineList;
    }

    private List<PrinterLine> printSmallTicketOrderItemDetail_SetMenu(List<ItemDetail> itemDetailList, boolean zh) throws Exception {
        logger.info("add item detail {} ", StringUtils.join(itemDetailList, ","));
        List<PrinterLine> printerLineList = new ArrayList<>();

        for (ItemDetail itemDetail : itemDetailList) {
            //套餐打印
            List<String> nameList = itemDetail.getNameAndPriceList().stream().map(detail -> {
                String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                return nameAndPriceName;
            }).collect(Collectors.toList());


            String space = printerClient.generateSpace(zh ? 14 : 22 - 7);
            String detailContentString = StringUtils.join(nameList, ", ");
            //如果有换行，如果换行处理
            List<String> contentList = printerClient.getStringList(detailContentString, zh ? LINE_LENGTH - 14 : LINE_LENGTH - 22 + 7, zh);

            for (String content : contentList) {
                PrinterLine printerLine = new PrinterLine();
                printerLine.setDirect(true);
                PrinterItem printerItem = new PrinterItem();
                printerItem.setContent(space + content);
                printerLine.add(printerItem);
                printerLineList.add(printerLine);
            }
        }

        return printerLineList;
    }

    /**
     * 打印订单规格项, 整个订单打印
     *
     * @param itemDetailList
     * @return
     */
    private List<PrinterLine> printSmallTicketOrderItemDetail(List<ItemDetail> itemDetailList, boolean zh) {
        logger.info("add item detail {} ", StringUtils.join(itemDetailList, ","));
        List<PrinterLine> printerLineList = new ArrayList<>();

        for (ItemDetail itemDetail : itemDetailList) {
            //非套餐打印
            List<String> nameList = itemDetail.getNameAndPriceList().stream().map(detail -> {
                String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                return nameAndPriceName;
            }).collect(Collectors.toList());

            String space = printerClient.generateSpace(10);
            String detailContentString = StringUtils.join(nameList, ", ");
            //如果有换行，如果换行处理
            List<String> contentList = printerClient.getStringList(detailContentString, LINE_LENGTH - 18, zh);

            for (String content : contentList) {
                PrinterLine printerLine = new PrinterLine();
                printerLine.setDirect(true);
                PrinterItem printerItem = new PrinterItem();
                printerItem.setContent(space + content);
                printerLine.add(printerItem);
                printerLineList.add(printerLine);
            }
        }

        return printerLineList;
    }

    /**
     * 订单在商铺的唯一编号
     *
     * @param orderNo
     * @return
     */
    private String getOrderNo(Integer orderNo) {
        String orderIdStr = orderNo.toString();

        if (orderIdStr.length() < 10) {
            int appendLength = 10 - orderIdStr.length();
            StringBuffer stringBuffer = new StringBuffer();

            for (int i = 0; i < appendLength; i++) {
                stringBuffer.append("0");
            }

            stringBuffer.append(orderIdStr);
            return stringBuffer.toString();
        } else {
            return orderIdStr;
        }
    }

    /**
     * 打印订单的小票
     * <p>
     * 包含客人小票，是否已支付，还是未支付，外卖的聚餐码
     *
     * @param order
     * @param packingOrder 是否打印整个订单
     * @return
     */
    public boolean printOrder(Order order, Long printerId, boolean packingOrder, boolean printerCustomerSignature) throws Exception {
        if (!config.canPrint()) {
            return true;
        }
        //空订单直接返回
        if (order == null) {
            logger.info("empty orders");
            return true;
        }
        //没有菜品的订单不打印
        if (isEmpty(order.getOrderItemDetailList())) {
            logger.info("no dishes in order {}", order);
            return true;
        }
        //修改订单支付类型不打印
        if (Constant.isOrderPayModifyRequest()) {
            logger.info("its order pay modify request");
            return true;
        }

        Order printerOrder = new Order();
        BeanUtils.copyProperties(order, printerOrder);
        order = printerOrder;

        //如果是外卖订单，直接成外卖
        if (getInt(order.getOrderType()) == ORDER_TYPE_TAKE_OUT || getInt(order.getOrderType()) == ORDER_TYPE_TAKE_OUT_PLAT) {
            for (OrderItem orderItem : getList(order.getOrderItemDetailList())) {
                orderItem.setTakeout(true);
            }
        }

        Long shopId = order.getShopId();
        Shop shop = ShopService.getInstance().findShopById(shopId);
        Company company = commonService.findEntity(shop.getCompanyId(), Company.class);
        Printer barCounterPrinter = commonService.findEntity(printerId, Printer.class);

        if (getBoolean(barCounterPrinter.getFlagDelete())) {
            logger.info("delete printer");
            return true;
        }

        boolean zh = commonService.isZh(barCounterPrinter.getLang());

        //生成打印字符串
        List<PrinterLine> printerLines = new ArrayList<>();

        //打印机的LOGO
        printerLines.add(printerClient.newLogo());

        //如果是打包单，添加打包单的描述
        if (packingOrder) {
            PrinterLine printerLine = printerClient.newLine();
            StringBuilder sb = new StringBuilder();
            int labelPackingSize = printerClient.getGbkLength(config.label_packing_order(zh));
            int prefixStarSize = (LINE_LENGTH / 2 - labelPackingSize) / 2;
            sb.append(printerClient.generateCh(prefixStarSize, "*"));
            sb.append(config.label_packing_order(zh));
            sb.append(printerClient.generateCh(prefixStarSize, "*"));
            printerLine.getPrinterItem().setContent(printerClient.appendDouble(sb.toString()));
            printerLines.add(printerLine);

            //添加空行
            printerLines.add(printerClient.emptyLine());
        }

        //如果是foodpanda的小票，在最顶上加一行
        if (getInt(order.getOrderType()) == ORDER_TYPE_TAKE_OUT_PLAT) {
            printerLines.add(printerClient.newLine(kitchenService.printBlackGround(CommonPrintService.getInstance().getTakeoutLabel(order, zh, config.label_take_out_plat(zh)) + "  " + "#" + Convert.toStr(order.getTakeOutNumber())), true, true));
            printerLines.add(printerClient.emptyLine());
        }


        if (isNotEmpty(company.getPrintCompanyName())) {
            //公司名称
            printerLines.add(printerClient.newLine(company.getPrintCompanyName(), true, true));
        } else {
            printerLines.add(printerClient.newLine(companyService.getCompanyName(company, zh), true, true));
        }

        //餐厅名称
        printerLines.add(printerClient.newLine("(" + langService.getShopName(shop, zh) + ")", true, null));

        //餐厅地址
        printerLines.addAll(CommonPrintService.getInstance().getShopAddressLine(shop, zh));

        //餐厅电话
        if (isNotEmpty(shop.getPhone())) {
            printerLines.add(printerClient.newLine(config.label_phone(zh) + getString(shop.getPhone()), null, null));
        }

        //分隔符
        printerLines.add(printerClient.printSeparator());

        //每日订单,是在餐桌点餐堂食场景
        if (orderService.isFoodTableOrder(order)) {
            PrinterLine orderNoLine = new PrinterLine();
            PrinterItem orderNoLabelItem = new PrinterItem();
            String perDayOrderNo = null;
            if (getBoolean(zh)) {
                perDayOrderNo = config.label_per_day_order(zh) + "：";
                orderNoLabelItem.setContent(perDayOrderNo);
            } else {
                perDayOrderNo = config.label_per_day_order(zh) + ":";
                orderNoLabelItem.setContent(perDayOrderNo);
            }

            if (!orderService.isFoodTableOrder(order)) {
                orderNoLabelItem.setDoubleShow(true);
                orderNoLabelItem.setBold(true);
            }

            orderNoLine.add(orderNoLabelItem);

            //用unicode去查询订单
            PrinterItem orderNoItem = new PrinterItem();
            String orderNoStr = getOrderNoStr(order);

            orderNoItem.setContent(orderNoStr);

            if (!orderService.isFoodTableOrder(order)) {
                orderNoItem.setBold(true);
                orderNoItem.setDoubleShow(true);
            }

            orderNoLine.add(orderNoItem);
            printerLines.add(orderNoLine);
        } else if (isTangShiQfOrder(order) || isTakeOutOrder(order)) {
            //总二维的堂食或者外卖，添加聚餐码
            PrinterLine takeNoLine = printerClient.newTwoItemLine(config.label_take_no(zh), order.getOrderNo() + "", true, true);
            printerLines.add(takeNoLine);

            //如果还有姓名，则显示姓名
            if (isNotEmpty(order.getUserName())) {
                printerLines.add(printerClient.newTwoItemLine(config.label_userName(zh), order.getUserName(), true, true));
            }

            //如果还有电话号码，则显示电话号码
            if (isNotEmpty(order.getContact())) {
                printerLines.add(printerClient.newTwoItemLine(config.label_contact(zh), order.getContact(), true, true));
            }
        }

        //如果有餐号，则添加餐号
        if (orderService.isFoodTableOrder(order)) {
            String code = null;
            if (order.getShowNo() != null) {
                code = order.getCode() + "-" + order.getShowNo();
            } else {
                code = order.getCode();
            }

            printerLines.add(printerClient.newTwoItemLine(config.label_food_table_no(zh), code, true, true));
        } else if (isTangShiQfOrder(order)) {
            //总二维码堂食
            printerLines.add(printerClient.newLine(printerClient.appendDouble(config.label_tang_shi(zh))));
            printerLines.add(printerClient.newTwoItemLine(config.label_take_out_time(zh), order.createDate, null, null));
        } else if (isTakeOutOrder(order)) {

            //外卖订单
            printerLines.add(printerClient.newLine(printerClient.appendDouble(CommonPrintService.getInstance().getTakeoutLabel(order, zh, config.label_take_out(zh)))));

            //打印外卖开单时间
            printerLines.add(printerClient.newTwoItemLine(config.label_take_out_time(zh), order.createDate, null, null));
        }

        //餐桌订单才打印开台时间
        if (orderService.isFoodTableOrder(order)) {
            printerLines.add(printerClient.newTwoItemLine(config.label_open_time(zh), order.createDate, null, null));
        }

        //如果填写了就餐人数则添加打印
        if (getInt(order.getPersons()) > 0) {
            printerLines.add(printerClient.newTwoItemLine(config.label_dinner_number(zh), order.getPersons() + "", null, null));
        }

        //订单备注
        if (isNotEmpty(order.getRemarks())) {
            printerLines.add(printerClient.printLineAsterisk());
            printerLines.add(printerClient.newLine(order.getRemarks(), true));
            printerLines.add(printerClient.printLineAsterisk());
        }

        //如果有服务员，那么添加显示服务员
        if (isNotEmpty(order.getWaiterName())) {
            printerLines.add(printerClient.newTwoItemLine(config.label_waiter_name(zh), order.getWaiterName(), null, null));
        }

        //标题
        printerLines.add(printerClient.newThreeItemLine(config.label_count(zh), config.label_name(zh), config.label_fee(zh), null));

        //两行分隔符
        printerLines.add(printerClient.printTwoLineSeparator());

        //具体的商品
        /*******************************************************************打印具体的菜品细节********************************************************************/
        if (isNotEmpty(order.getOrderItemDetailList())) {
            List<PrinterLine> itemDetailList = printSmallTicketOrderItem(order, zh, packingOrder);
            printerLines.addAll(itemDetailList);
        }
        /*******************************************************************打印具体的菜品细节********************************************************************/

        //两行分隔符
        printerLines.add(printerClient.printTwoLineSeparator());

        //************************************************************************************************************************************************************************
        //打印子菜单部分
        //************************************************************************************************************************************************************************

        //如果是分菜，分钱的订单，那么需要打印总的订单的部分
        if (!getBoolean(order.getParentOrder()) && Arrays.asList(USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED, USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON, USER_SELECT_PAY_TYPE_PART_FOOD).contains(getInt(order.getUserSelectPayType()))) {
            Long parentOrderId = order.getParentOrderId();

            Order parentOrder = orderService.findOrder(order.getShopId(), parentOrderId);
            //父订单的小计,只有分钱结账的时候才打印
            if (Arrays.asList(USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED, USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON).contains(getInt(order.getUserSelectPayType()))) {
                //小计
                printerLines.add(printerClient.newTwoItemLine(config.label_small_total(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(parentOrder.getCostOrigin()))), null, null));
                //添加服务费，如果存在
                //如果有服务费，填写服务费
                if (showMoneyDouble(parentOrder.getServiceFee()) > 0) {
                    printerLines.add(printerClient.newTwoItemLine(config.label_service_fee(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(parentOrder.getServiceFee()))), null, null));
                }

                //添加消费税，如果存在
                //如果有消费税，打印消费税
                if (showMoneyDouble(parentOrder.getConsumptionTax()) > 0) {
                    printerLines.add(printerClient.newTwoItemLine(config.label_consumptionTax_fee(zh, showMoneyDouble(shop.getShopConfig().getConsumptionTax())), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(parentOrder.getConsumptionTax()))), null, null));
                }

                //总订单的总计
                double userTotalCost = showMoneyDouble(getDouble(parentOrder.getUserCost()));
                PrinterLine totalLine = printerClient.newTwoItemLine(config.label_order_total(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(userTotalCost)), null, null);
                printerLines.add(totalLine);

                //两行分隔符
                printerLines.add(printerClient.printTwoLineSeparator());
            }

            //打印子单的数据
            //添加應付
            printerLines.add(printerClient.newTwoItemLine(config.label_should_pay(zh), "", null, null));

            //小計
            printerLines.add(printerClient.newTwoItemLine(config.label_small_total(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getCostOrigin()))), null, null));

        } else {
            //小计
            printerLines.add(printerClient.newTwoItemLine(config.label_small_total(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getCostOrigin()))), null, null));
        }

        if (!equals(order.getOrderType(), ORDER_TYPE_TAKE_OUT_PLAT)) {

            //优惠信息
            if (getDouble(order.getDiscountFee()) > 0) {
                printerLines.add(printerClient.newTwoItemLine(config.label_discount_info(zh), "-$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getDiscountFee()))), null, null));
            }

            //外卖优惠信息
            if (getDouble(order.getTakeOutDiscountFee()) > 0) {
                printerLines.add(printerClient.newTwoItemLine(config.label_take_out_discount_fee(zh), "-$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getTakeOutDiscountFee()))), null, null));
            }

            //如果有服务费，填写服务费
            if (showMoneyDouble(order.getServiceFee()) > 0) {
                printerLines.add(printerClient.newTwoItemLine(config.label_service_fee(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getServiceFee()))), null, null));
            }

            //添加配送费，如果存在
            //如果有配送费，打印配送费
            if (showMoneyDouble(order.getDeliveryFee()) > 0) {
                printerLines.add(printerClient.newTwoItemLine(config.label_delivery_fee(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getDeliveryFee()))), null, null));
            }

            //如果有消费税，打印消费税
            if (showMoneyDouble(order.getConsumptionTax()) > 0) {
                printerLines.add(printerClient.newTwoItemLine(config.label_consumptionTax_fee(zh, showMoneyDouble(shop.getShopConfig().getConsumptionTax())), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getConsumptionTax()))), null, null));
            }

            //如果有小费，打印小费
            if (showMoneyDouble(order.getTipsFee()) > 0) {
                printerLines.add(printerClient.newTwoItemLine(config.label_tips_fee(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getTipsFee()))), null, null));
            }

            //如果有餐盒费，打印
            //必须要有餐盒的时候打印
            if (order.getPackageFee() != null && showDouble(order.getPackageFee()) != 0) {
                printerLines.add(printerClient.newTwoItemLine(config.label_lunch_box(zh), "$" + showMoneyDouble(order.getPackageFee()), null, null));
            }
        }

        Boolean totalDouble = getTotalDouble(packingOrder);

        //总计
        double userTotalCost = 0d;
        String useUserCostInThread = ThreadContext.get(THREAD_LOCAL_VARIABLE_USE_USER_COST);

        if (useUserCostInThread != null) {
            userTotalCost = showMoneyDouble(getDouble(order.getUserCost()));
        } else if (getBoolean(order.getParentOrder())) {
            if (order.getStatus() == ORDER_STATUS_END) {
                userTotalCost = showMoneyDouble(getDouble(order.getUserCost()));
            } else {
                userTotalCost = showMoneyDouble(getDouble(order.getUserCost()) - getDouble(order.getDiscountFee()));
            }
        } else {
            userTotalCost = showMoneyDouble(getDouble(order.getUserCost()));
        }

        if (userTotalCost < 0) {
            userTotalCost = 0d;
        }

        PrinterLine totalLine = printerClient.newTwoItemLine(config.label_order_total(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(userTotalCost)), null, totalDouble);

        if (getBoolean(totalDouble)) {
            totalLine.getItemList().get(0).setDoubleShow(true);
        }

        printerLines.add(totalLine);

        Boolean payTypeDouble = getPayTypeDouble(packingOrder);

        /**支付方式**/
        if (orderService.isOrderPayed(order)) {
            //如果还有现金支付，那么显示支付了多少，返回了多少
            List<CashPay> otherPayTypeList = getList(order.getCashPayList());
            List<PayType> payTypeList = payTypeService.findPayTypeListCache_Stripe(order.getShopId());

            for (CashPay cashPay : otherPayTypeList) {
                PayType payType = payTypeService.filterPayType(payTypeList, cashPay.getPayType());

                //stripe支付需要控制到具体的银行卡
                if (payType.getType() == ORDER_PAY_TYPE_STRIPE) {
                    printerLines.add(printerClient.newTwoItemLine(order.getSubStripePayType(), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(cashPay.getPayCash()))), payTypeDouble, payTypeDouble));
                } else if (payType.getType() != ORDER_PAY_TYPE_CASH) {
                    printerLines.add(printerClient.newTwoItemLine(payTypeService.getPayTypeName(payType, zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(cashPay.getPayCash()))), payTypeDouble, payTypeDouble));
                } else {
                    printerLines.add(printerClient.newTwoItemLine(config.label_cash_receive(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(cashPay.getPayCash()))), payTypeDouble, payTypeDouble));
                    printerLines.add(printerClient.newTwoItemLine(config.label_cash_return(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(cashPay.getReturnCash()))), payTypeDouble, payTypeDouble));
                }
            }
        } else {
            printerLines.add(printerClient.newTwoItemLine(config.label_unpay(zh), "$" + BigDecimalUtil.format(BigDecimal.valueOf(showMoneyDouble(order.getLeftCash()))), payTypeDouble, payTypeDouble));
        }

        //如果是支付完成的订单，包含分菜结账的单，然后又开启了签名功能，那么打印签名的地方
        if (config.isHkVersion() && getBoolean(shop.getShopConfig().getCustomerSign())) {
            if (canGenerateCustomerSignature(printerCustomerSignature, order)) {
                printerLines.addAll(generateCustomerSign(zh));
            }
        }

        //如果是stripe刷卡机打印
        boolean printMerchantCopy = ThreadContext.get(THREAD_LOCAL_VARIABLE_PRINT_MERCHANT_COPY) != null;

        if (getBoolean(order.getStripeTerminal()) && printMerchantCopy) {
            printerLines.add(printerClient.emptyLine());
            printerLines.add(printerClient.newTwoItemLine(config.us_tips_fee(zh), "$________________", null, null));
            printerLines.add(printerClient.emptyLine());
            printerLines.add(printerClient.newTwoItemLine(config.us_total(zh), "$________________", null, null));
            printerLines.add(printerClient.emptyLine());
            printerLines.add(printerClient.emptyLine());
            printerLines.add(printerClient.newLine("APPROVED", true, true));
            printerLines.add(printerClient.emptyLine());
            printerLines.add(printerClient.emptyLine());
            printerLines.add(printerClient.newLine("X" + printerClient.generateSeparator(PrinterClient.LINE_LENGTH - 1, "-")));

            //添加持卡人名字
            {
                PrinterLine printerLine = printerClient.newLine(printerClient.appendHeight(stringService.getString(order.getCardHolderName(), "") + "****" + stringService.getString(order.getLast4(), "")), true, null);
                printerLines.add(printerLine);
            }

            //添加其它信息
            {
                PrinterLine printerLine = printerClient.newLine();
                StringBuilder sb = new StringBuilder();
                sb.append(printerClient.appendCenter("I AGREE TO PAY THE ABOVE TOTAL"));
                sb.append(printerClient.appendCenter("AMOUNT ACCORDING TO CARD ISSUER"));
                sb.append(printerClient.appendCenter("AGREEMENT(MERCHANT AGREEMENT"));
                sb.append(printerClient.appendCenter("IF CREDIT VOUCHER)"));
                printerLine.getPrinterItem().setContent(sb.toString());
                printerLines.add(printerLine);
            }

            printerLines.add(printerClient.printSeparator());

            //添加小费建议
            {
                printerLines.add(printerClient.newLine("Suggested Tips", true, null));

                orderService.calTips(order.getUserCost(), order);
                for (CalTips calTips : order.getCalTipsList()) {
                    //添加每种支付的金额
                    StringBuffer sb = new StringBuffer();
                    //比例
                    sb.append(printerClient.centerLength(String.format("%s.00%% of sale:", calTips.getPercent()), LINE_LENGTH / 3));
                    //小费
                    sb.append(printerClient.centerLength(String.format("$%s =", showDouble(calTips.getTips())), LINE_LENGTH / 3));
                    //金额
                    sb.append(printerClient.centerLength(String.format("$%s", showDouble(calTips.getUserCost())), LINE_LENGTH / 3));
                    printerLines.add(printerClient.newLine(sb.toString()));
                }
            }

            printerLines.add(printerClient.printSeparator());
        }

        //客票条形码
        if (getBoolean(shop.getShopConfig().getPrinterEndBarCode())) {
            //两行分隔符
            printerLines.add(printerClient.printTwoLineSeparator());

            //添加条形码
            printerLines.add(printerClient.newBarCode(getOrderNo(order.getOrderNo())));

            //两行分隔符
            printerLines.add(printerClient.printTwoLineSeparator());
        }


        //商家特别信息临时删除掉
        //添加商家特别信息
        if (getBoolean(shop.getShopConfig().getShopInfoOpen()) && canGenerateCustomerSignature(printerCustomerSignature, order)) {
            //居中，放大显示
            String shopInfo = zh ? shop.getShopConfig().getShopInfo_zh() : shop.getShopConfig().getShopInfo_en();
            if (isNotEmpty(shopInfo)) {
                shopInfo = printerClient.appendCenter(shopInfo);
                printerLines.add(printerClient.newLine(shopInfo));
                //两行分隔符
                printerLines.add(printerClient.printTwoLineSeparator());
            }
        }

        //如果有生成的优惠卷信息，则添加
        if (order.getSatisfyAndCutCode() != null) {
            printerClient.newLine(printerClient.appendDouble(config.label_discount_info(zh)));
            //查询优惠卷
            DiscountTicket discountTicket = DiscountTicketService.getInstance().findTicketByCode(order.getSatisfyAndCutCode(), company.getId());
            Long parentTicketId = discountTicket.getParentId();
            DiscountTicket parentTicket = DiscountTicketService.getInstance().findTicket(parentTicketId);

            printerLines.add(printerClient.newLine(config.label_satisfy(zh) + (zh ? "$" : " $") + showMoneyDouble(parentTicket.getAtLeastCost()), null, null));

            if (zh) {
                printerLines.add(printerClient.newLine(String.format(config.label_satisfy_and_cut(zh), showMoneyDouble(discountTicket.getAtLeastCost()), showMoneyDouble(discountTicket.getDiscountCash())), null, null));
            } else {
                //英文分两行
                printerLines.add(printerClient.newLine(String.format("You earned a coupon that is get $%s off when", showMoneyDouble(discountTicket.getDiscountCash()))));
                printerLines.add(printerClient.newLine(String.format("spending more than $%s", showMoneyDouble(discountTicket.getAtLeastCost()))));
            }

            if (zh) {
                printerLines.add(printerClient.newLine(config.label_validate_day(zh) + DateUtil.format(discountTicket.getEndTime(), "yyyy年MM月dd日"), null, null));
            } else {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MMMM dd yyyy", Locale.ENGLISH);
                printerLines.add(printerClient.newLine("Valid Until " + simpleDateFormat.format(new Date(discountTicket.getEndTime())), null, null));
            }


            //添加优惠卷的条形码
            printerLines.add(printerClient.newBarCode(discountTicket.getCode()));
            //只有在最后告示开关开启之后，优惠卷加一行分割线
            if (getBoolean(company.getOpenReceiptExplain())) {
                printerLines.add(printerClient.printSeparator());
            }
        }

        if (getBoolean(order.getStripeTerminal()) && printMerchantCopy) {
            printerLines.add(printerClient.newLine("MERCHANT COPY", true, null));
        } else if (getBoolean(order.getStripeTerminal())) {
            printerLines.add(printerClient.newLine("CUSTOMER COPY", true, null));
        }
        if (getBoolean(company.getOpenReceiptExplain())) {
            //空一行
            printerLines.add(printerClient.emptyLine());
            printerLines.add(printerClient.newLine("Powered By DoLA Technology", true, false));
        }


        return printerClient.printList(printerLines, AES.decrypt(barCounterPrinter.getPrinterSn()), barCounterPrinter.getId());
    }

    /**
     * 添加签名
     *
     * @param zh
     * @return
     */
    private List<PrinterLine> generateCustomerSign(boolean zh) {
        if (zh) {
            List<PrinterLine> list = new ArrayList<>();
            list.add(printerClient.printSeparator());
            list.add(printerClient.emptyLine());
            list.add(printerClient.emptyLine());
            list.add(printerClient.newLine("簽署：" + printerClient.generateCh(LINE_LENGTH - printerClient.getGbkLength("簽署："), "_")));

            return list;
        } else {
            List<PrinterLine> list = new ArrayList<>();
            list.add(printerClient.printSeparator());
            list.add(printerClient.emptyLine());
            list.add(printerClient.emptyLine());
            //添加中间部分
            list.add(printerClient.newLine("Signature:" + printerClient.generateCh(LINE_LENGTH - printerClient.getGbkLength("Signature:"), "_")));
            return list;
        }

    }

    /**
     * 是否是总二维码堂食
     *
     * @param order
     * @return
     */
    private boolean isTangShiQfOrder(Order order) {
        return getInt(order.getOrderType()) == Constant.ORDER_TYPE_QUICK_FOOD;
    }

    /**
     * 是否是外卖订单
     *
     * @param order
     * @return
     */
    private boolean isTakeOutOrder(Order order) {
        return getInt(order.getOrderType()) == Constant.ORDER_TYPE_TAKE_OUT || getInt(order.getOrderType()) == ORDER_TYPE_TAKE_OUT_PLAT;
    }

    /**
     * 获取订单号
     *
     * @param order
     * @return
     */
    private String getOrderNoStr(Order order) {
        if (order == null) {
            return "";
        }

        String orderNoStr = "";

        Integer orderNo = order.getOrderNo();

        if (orderNo != null) {
            orderNoStr = orderNo + "";
        }

        if (order.getSubOrderId() != null) {
            orderNoStr = orderNoStr + "-" + order.getSubOrderId();
        }

        return orderNoStr;
    }

    /**
     * 打印排队信息
     *
     * @param lineUp
     */
    public boolean printLineConfig(LineUp lineUp, Long printerId, String touchDeviceUuid) throws Exception {
        Long shopId = lineUp.getShopId();
        Shop shop = ShopService.getInstance().findShopById(shopId);
        Company company = commonService.findEntity(shop.getCompanyId(), Company.class);
        Printer barCounterPrinter = commonService.findEntity(printerId, Printer.class);
        Boolean zh = commonService.isZh(barCounterPrinter.getLang());

        VerifyUtil.verify(() -> barCounterPrinter != null, ResponseStatus.BAR_COUNTER_PRINTER_NOT_CONFIG);
        String printerSn = AES.decrypt(barCounterPrinter.getPrinterSn());

        //生成打印字符串
        ArrayList<PrinterLine> printerLines = new ArrayList<>();

        //打印机的LOGO
        printerLines.add(printerClient.newLogo());

        if (isNotEmpty(company.getPrintCompanyName())) {
            //公司名称
            printerLines.add(printerClient.newLine(company.getPrintCompanyName(), true, true));
        } else {
            printerLines.add(printerClient.newLine(companyService.getCompanyName(company, zh), true, true));
        }

        //餐厅名称
        printerLines.add(printerClient.newLine("(" + langService.getShopName(shop, zh) + ")", true, null));

        //餐厅地址
        printerLines.addAll(CommonPrintService.getInstance().getShopAddressLine(shop, zh));

        //餐厅电话
        if (isNotEmpty(shop.getPhone())) {
            printerLines.add(printerClient.newLine(config.label_phone(zh) + getString(shop.getPhone()), null, null));
        }

        //分隔符
        printerLines.add(printerClient.printSeparator());

        //排队信息
        String code = printerClient.appendDoubleShowAndBold(lineUp.getCode() + lineUp.getSerial());
        printerLines.add(printerClient.newLine(config.label_line_up_no(zh) + code, true, null));

        //当前叫号
        LineUp firstLineUp = LineUpService.getInstance().getFirstLineUp(lineUp.getShopId(), lineUp.getCode());
        String firstCode = printerClient.appendDoubleShow(firstLineUp.getCode() + firstLineUp.getSerial());
        printerLines.add(printerClient.newLine(config.label_current_no(zh) + firstCode, true, null));

        //等候桌数
        printerLines.add(printerClient.newLine(config.label_wait_no(zh) + (lineUp.getSerial() - firstLineUp.getSerial()) + config.label_table(zh), true, null));

        //分隔符
        printerLines.add(printerClient.printSeparator());

        //排队时间
        printerLines.add(printerClient.newLine(config.label_wait_time(zh) + lineUp.getCreateDate(), null, null));

        //二维码
        String endPoint = config.getEndPoint();
        String qrCode = endPoint + "/customer/index.html/#/pages/lineupDetail?sid=%s&lid=%s";
        qrCode = String.format(qrCode, shopId, lineUp.getId());
        logger.info("the qr code is {}", qrCode);
        printerLines.add(printerClient.newQrCode(qrCode));

        if (getBoolean(shop.getShopConfig().getOpenQueueUpQRContent())) {
            //排队二维码下面 添加描述 中文
            if (zh && isNotEmpty(shop.getShopConfig().getQueueUpQRContent_zh())) {
                PrinterLine printerLine = printerClient.newLine(shop.getShopConfig().getQueueUpQRContent_zh(), true, null);
                printerLine.getPrinterItem().setDoubleShow(true);
                printerLines.add(printerLine);
            }
            //排队二维码下面 添加描述 英文
            if (!zh && isNotEmpty(shop.getShopConfig().getQueueUpQRContent_en())) {
                PrinterLine printerLine = printerClient.newLine(shop.getShopConfig().getQueueUpQRContent_en(), true, null);
                printerLine.getPrinterItem().setDoubleShow(true);
                printerLines.add(printerLine);
            }

        }


        return printerClient.printList(printerLines, printerSn, printerId);
    }

    /**
     * 打印闭店报告
     *
     * @param shopId
     * @param printerId
     * @param touchDeviceUuid
     * @param detailReport
     * @return
     * @throws Exception
     */
    public boolean printCloseReport(Long shopId, Long printerId, String touchDeviceUuid, DetailReport detailReport) throws Exception {
        return CloseReportPrintService.getInstance().printCloseReport(shopId, printerId, touchDeviceUuid, detailReport);
    }

    public static class PrintPayType {
        public String payTypeName;
        public int payType;
        public double vipFee;
        public double vipFeeAndOther;
    }

    /**
     * 添加打印平台的数据
     *
     * @param zh
     * @param shopId
     * @return
     */
    private PrinterLine addTakeOutPlat(Boolean zh, Long shopId) {
        if (zh == null || zh) {
            PrinterLine printerLine = printerClient.newLine();
            PrinterItem printerItem = printerLine.getPrinterItem();
            StringBuffer sb = new StringBuffer();
            //外卖平台标题
            sb.append(printerClient.appendSpace(config.close_report_take_out_plat(zh), LINE_LENGTH / 4));

            //添加两个空格距离
            sb.append(printerClient.generateSpace(LINE_LENGTH / 4));
            sb.append(printerClient.generateSpace(LINE_LENGTH / 4));
            //默认添加0
            sb.append(printerClient.centerLength("0.0", LINE_LENGTH / 4));

            printerItem.setContent(sb.toString());
            return printerLine;
        } else {
            //英文处理
            PrinterLine printerLine = printerClient.newLine();
            PrinterItem printerItem = printerLine.getPrinterItem();
            StringBuffer sb = new StringBuffer();
            sb.append(config.close_report_take_out_plat(zh));
            sb.append(printerClient.generateSpace(LINE_LENGTH / 4 * 3 - printerClient.getGbkLength(config.close_report_take_out_plat(zh))));
            //默认添加0
            sb.append(printerClient.centerLength("0.0", LINE_LENGTH / 4));
            printerItem.setContent(sb.toString());
            return printerLine;
        }
    }

    /**
     * 添加净营收
     *
     * @param zh
     * @param shopId
     * @return
     */
    private PrinterLine addUserCost(Boolean zh, Long shopId) throws Exception {
        StringBuilder sb = new StringBuilder();

        String userCostTitle = config.close_report_user_cost(zh);
        userCostTitle = printerClient.appendDouble(userCostTitle);

        Double userCost = showDouble(ReportService.getInstance().sumUserCost(shopId));
        int userCostLength = printerClient.getGbkLength(userCost) * 2;

        //前面的长度
        int titleLength = (LINE_LENGTH - userCostLength) / 2;
        sb.append(printerClient.appendDouble(printerClient.appendSpace(userCostTitle, titleLength)));
        sb.append(printerClient.appendDouble(userCost));

        return printerClient.newLine(sb.toString());
    }


    /**
     * 付款方式打印
     *
     * @param payType
     * @param label
     * @param printerLines
     * @param orderTypeForPrinterList
     */
    private void addPayTypeForCloseReport(Long payType, String
            label, ArrayList<PrinterLine> printerLines, List<Report> orderTypeForPrinterList) {
        List<Report> cashReportList = orderTypeForPrinterList.stream().filter(p -> p.getPayType() != null && p.getPayType().longValue() == payType).collect(Collectors.toList());
        if (cashReportList.size() > 0) {
            Optional<Report> tangShiOption = cashReportList.stream().filter(p -> p.getOrderType() != null && p.getOrderType() == Constant.ORDER_REPORT_TYPE_TANG_SHI).findFirst();
            double tangshiCash = 0d;
            if (tangShiOption.isPresent()) {
                tangshiCash = tangShiOption.get().getValue();
            }

            Optional<Report> takeOutOption = cashReportList.stream().filter(p -> p.getOrderType() != null && p.getOrderType().longValue() == Constant.ORDER_REPORT_TYPE_TAKE_OUT).findFirst();
            double takeOutCash = 0d;
            if (takeOutOption.isPresent()) {
                takeOutCash = takeOutOption.get().getValue();
            }

            printerLines.add(printerClient.newThreeItemLine(label, tangshiCash + "", takeOutCash + "", null));
        }
    }

    /**
     * 查询当前餐厅除了该打印机之外的所有打印机
     *
     * @param shopId
     * @param printerId
     * @return
     */
    public List<Printer> findPrinterListExceptOne(Long shopId, Long printerId) {
        List<Printer> allShopPrinters = ShopService.getInstance().findAllShopPrinters(shopId);

        if (printerId == null) {
            return allShopPrinters;
        }

        return allShopPrinters.stream().filter(p -> p.getId().longValue() != printerId.longValue()).collect(Collectors.toList());
    }

    /**
     * 查询当前餐厅除了该打印机之外的所有打印机标签
     *
     * @param shopId
     * @param printerId
     * @return
     */
    public List<String> findAllPrinterLabelExceptOne(Long shopId, Long printerId) {
        List<Printer> printerList = findPrinterListExceptOne(shopId, printerId);

        List<String> otherPrinterLabelList = printerList.stream().filter(p -> isNotEmpty(p.getPrinterLabelList()))
                .flatMap(p -> p.getPrinterLabelList().stream()).collect(Collectors.toList());

        logger.info("otherPrinterLabelList is {}", StringUtils.join(otherPrinterLabelList, ","));

        return otherPrinterLabelList;
    }

    /**
     * 检查打印标签的合法性
     * printerId为空的时候，就是创建打印机
     *
     * @param printerId
     * @param printerLabelList
     */
    public void checkPrinterLabelValid(Long shopId, Long printerId, List<String> printerLabelList) throws
            Exception {
        if (isEmpty(printerLabelList)) {
            logger.info("empty printer label list");
            return;
        }

        List<String> allPrinterLabelList = findAllPrinterLabelExceptOne(shopId, printerId);

        if (isEmpty(allPrinterLabelList)) {
            logger.info("all other printer label is empty");
            return;
        }

        for (String printerLabel : printerLabelList) {
            VerifyUtil.verify(() -> !allPrinterLabelList.contains(printerLabel), ResponseStatus.SOME_PRINTER_LABEL_BIND);
        }
    }

    /**
     * 刷新打印机的状态
     *
     * @param shopId
     * @return
     * @throws ResponseStatusException
     */
    public List<Printer> flushPrinterStatus(Long shopId) throws ResponseStatusException {
        List<Printer> allShopPrinters = ShopService.getInstance().findAllShopPrinters(shopId);

        for (Printer printer : allShopPrinters) {
            printerClient.flushPrinterStatus(printer);
        }

        return allShopPrinters;
    }


    /**
     * 清空打印机的KEY, 以及SN
     *
     * @param printer
     */
    public void clearDefaultSn(Printer printer) {
        if (printer == null) {
            return;
        }

        if (equals(printer.getPrinterSn(), Constant.USER_DEFAULT_PASSWORD)) {
            printer.setPrinterSn(null);
        }

        if (equals(printer.getPrinterKey(), Constant.USER_DEFAULT_PASSWORD)) {
            printer.setPrinterKey(null);
        }
    }

    /**
     * 将
     *
     * @param shopId
     */
    public void setOtherPrinterNotPrinterPayedOrderInC(Long shopId) throws Exception {
        List<Printer> printerList = ShopService.getInstance().findPrinterList(shopId);
        for (Printer printer : printerList) {
            if (getBoolean(printer.getPrintPayedOrder())) {
                printer.setPrintPayedOrder(false);
                commonService.save(printer);
            }
        }
    }

    /**
     * 设置其它打印不能打印C端的订单
     *
     * @param p
     * @throws Exception
     */
    public void setOtherPrinterInCFalse(Printer p) {
        //如果配置了客户端打印机，那么其它打印机的客户端打印机将清空
        try {
            Printer printerInDb = CommonService.getInstance().findEntity(p.getId(), Printer.class);

            if (getBoolean(printerInDb.getPrintOrderInC())) {
                List<Printer> printerList = ShopService.getInstance().findPrinterList(printerInDb.getShopId());
                List<Printer> otherPrinterList = printerList.stream().filter(temp -> !equals(printerInDb.getId(), temp.getId())).collect(Collectors.toList());
                for (Printer printer1 : otherPrinterList) {
                    printer1.setPrintOrderInC(false);
                    commonService.save(printer1);
                }

                //同步打印失败的任务
                PrinterFailedResult printerFailedResult = new PrinterFailedResult();
                printerFailedResult.setShopId(printerInDb.getShopId());
                printerFailedResult.setPrintType(PRINTER_FAILED_TYPE_C_END);
                List<PrinterFailedResult> printerFailedResultList = commonService.searchAll(printerFailedResult);

                String printerSn = AES.decrypt(printerInDb.getPrinterSn());
                for (PrinterFailedResult failedResult : printerFailedResultList) {
                    String printInfo = PrinterClient.getInstance().printInfo(printerSn, failedResult.getPrintDetailJson());
                    //成功后删除任务
                    if (PrinterClient.getInstance().isPrinterOk(printInfo)) {
                        commonService.delete(failedResult, false, null);
                    }
                }
            }

            //只能有一个打印机可以是打包单的打印机
            if (getBoolean(printerInDb.getPacking())) {
                List<Printer> printerList = ShopService.getInstance().findPrinterList(printerInDb.getShopId());
                //将剩下的打印机设置成false
                printerList.stream().filter(p1 -> !equals(p1.getId(), printerInDb.getId())).forEach(printer -> {
                    printer.setPacking(false);

                    try {
                        commonService.save(printer);
                    } catch (Exception e) {
                        logger.error("e", e);
                    }
                });

                //同步打印失败的任务
                PrinterFailedResult printerFailedResult = new PrinterFailedResult();
                printerFailedResult.setShopId(printerInDb.getShopId());
                printerFailedResult.setPrintType(PRINTER_FAILED_TYPE_PACKING);
                List<PrinterFailedResult> printerFailedResultList = commonService.searchAll(printerFailedResult);

                String printerSn = AES.decrypt(printerInDb.getPrinterSn());
                for (PrinterFailedResult failedResult : printerFailedResultList) {
                    String printInfo = PrinterClient.getInstance().printInfo(printerSn, failedResult.getPrintDetailJson());
                    //成功后删除任务
                    if (PrinterClient.getInstance().isPrinterOk(printInfo)) {
                        commonService.delete(failedResult, false, null);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 查询失败任务
     *
     * @param touchUuid
     */
    public List<PrinterFailedResult> queryPrinterFailedResult(String touchUuid) {
        PrinterFailedResult printerFailedResult = new PrinterFailedResult();
        printerFailedResult.setTouchUuid(touchUuid);
        return commonService.searchAll(printerFailedResult);
    }

    /**
     * 是否可以打印客人签名
     *
     * @param printerCustomerSignature
     * @param order
     * @return
     */
    public boolean canGenerateCustomerSignature(Boolean printerCustomerSignature, Order order) {
        if (printerCustomerSignature) {
            //前端发送的，要打印客人标签
            return true;
        } else if (!getBoolean(order.getParentOrder()) && getBoolean(order.getPayed())) {
            //子订单，并且已经支付了
            return true;
        } else if (getBoolean(order.getParentOrder()) && getInt(order.getStatus()) == ORDER_STATUS_END) {
            //父订单，并且全部支付完成
            return true;
        }

        return false;
    }


    /**
     * 查找配置了下单成功后的打印机
     *
     * @param shopId
     * @return
     */
    public Optional<Printer> findPrinterWithPayedOrder(Long shopId) {
        Printer printer = new Printer();
        printer.setShopId(shopId);
        printer.setPrintPayedOrder(true);
        return commonService.searchOneOptional(printer);
    }

    public Boolean getPayTypeDouble(boolean packingOrder) {
        if (packingOrder) {
            return true;
        }

        return null;
    }

    public Boolean getTotalDouble(boolean packingOrder) {
        if (packingOrder) {
            return null;
        }

        return true;
    }


    public String getPrintContent(String content, boolean packingOrder) {
        if (packingOrder) {
            return printerClient.appendHeightAndBold(content);
        }

        return content;
    }

}
